# logger_utils.py
import logging
import logging.handlers
import sys
import os
from typing import Optional
from multiprocessing import Queue, current_process
import threading

__all__=['get_logger']

# === 全局状态 ===
_initialized = False
_log_queue: Optional[Queue] = None
_queue_listener: Optional[logging.handlers.QueueListener] = None
_initialization_lock = threading.Lock()  # 保护初始化

_formatter = logging.Formatter(
    # fmt="%(asctime)s | %(levelname)-8s | %(processName)s/%(threadName)s | %(filename)s:%(lineno)d - %(funcName)s() | %(message)s",
    fmt="%(asctime)s.%(msecs)03d [ %(levelname)s | %(name)s | %(filename)s:%(lineno)d ] %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"  # 使用默认格式，毫秒由 formatTime 添加  "%Y-%m-%d %H:%M:%S"
)

# 第三方库日志级别配置
_THIRD_PARTY_LOGGERS = {
    'urllib3': logging.WARNING,
    'requests': logging.WARNING,
    'boto3': logging.WARNING,
    'botocore': logging.WARNING,
    's3transfer': logging.WARNING,
    'PIL': logging.WARNING,
    'matplotlib': logging.WARNING,
    'sqlalchemy.engine': logging.WARNING,
    'paramiko': logging.WARNING,
    'chardet': logging.WARNING,
    'httpx': logging.WARNING,
    'httpcore': logging.WARNING,
    'werkzeug': logging.WARNING,
    'flask': logging.WARNING,
    "celery": logging.WARNING,
    "celery.worker": logging.WARNING,
    "celery.app": logging.WARNING,
    "celery.beat": logging.WARNING,
    "celery.concurrency": logging.WARNING,
    "gunicorn.access": logging.WARNING,
}


def _is_main_process():
    return current_process().name == 'MainProcess'


def _remove_handlers_from_all_loggers():
    """移除所有非 root logger 的 handlers，防止第三方库自定义输出"""
    manager = logging.root.manager
    for logger_name in manager.loggerDict:
        logger = logging.getLogger(logger_name)
        if logger.handlers:
            logger.propagate = True
            logger.handlers.clear()


def _setup_queue_listener(log_path: Optional[str]):
    global _log_queue, _queue_listener

    handlers = []

    # 1. 控制台输出
    console = logging.StreamHandler(sys.stdout)
    console.setFormatter(_formatter)
    console.setLevel(logging.INFO)
    handlers.append(console)

    # 2. 文件输出（仅主进程）
    if log_path and _is_main_process():
        os.makedirs(os.path.dirname(log_path) if os.path.dirname(log_path) else '.', exist_ok=True)
        # file_handler = logging.FileHandler(log_path, mode='a', encoding='utf-8')
        file_handler = logging.handlers.TimedRotatingFileHandler(
            filename=log_path,
            when='midnight',        # 每天分割
            interval=1,             # 间隔 1 天
            backupCount=7,          # 保留最近 7 天的日志，可根据需要调整
            encoding='utf-8',
            utc=False               # 使用本地时间
        )
        file_handler.setFormatter(_formatter)
        file_handler.setLevel(logging.DEBUG)
        handlers.append(file_handler)

    # 创建队列和监听器
    _log_queue = Queue(-1)
    _queue_listener = logging.handlers.QueueListener(
        _log_queue,
        *handlers,
        respect_handler_level=True
    )
    _queue_listener.start()

    # 注册关闭
    import atexit
    atexit.register(lambda: _queue_listener.stop())


def get_logger(log_name: str = "root", log_path: Optional[str] = None) -> logging.Logger:
    global _initialized

    logger = logging.getLogger(log_name)
    if logger.handlers:
        return logger  # 已配置，直接返回

    with _initialization_lock:
        if not _initialized:
            _initialized = True

            # 👉 清理所有已存在的 handler（防止第三方库提前添加）
            _remove_handlers_from_all_loggers()

            # 👉 只在主进程启动 QueueListener
            if _is_main_process():
                _setup_queue_listener(log_path)

            # 👉 配置 root logger 为唯一输出源
            root_logger = logging.getLogger()
            root_logger.setLevel(logging.DEBUG)
            root_logger.handlers.clear()  # 确保干净

            if _log_queue is not None:
                queue_handler = logging.handlers.QueueHandler(_log_queue)
                queue_handler.setLevel(logging.DEBUG)
                root_logger.addHandler(queue_handler)
            else:
                # fallback：控制台输出
                console = logging.StreamHandler(sys.stdout)
                console.setFormatter(_formatter)
                console.setLevel(logging.INFO)
                root_logger.addHandler(console)

            # 👉 设置第三方库日志级别
            for name, level in _THIRD_PARTY_LOGGERS.items():
                logging.getLogger(name).setLevel(level)

    return logging.getLogger(log_name)